﻿using CTM.Web.Filters;
using CTM.Web.Models.View.Account;
using CTM.Web.Models.View.Feedback;
using CTM.Web.Models.View.Home;
using CTM.Web.Models.View.Notification;
using CTM.Web.Services;
using CTM.Web.Utils;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using System;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;

namespace CTM.Web.Controllers
{
    public class HomeController : Controller
    {
        // initialize service objects
        private IPostService postService;
        private IAccountService accountService; // employee or user service
        private IOrgService orgService;
        private ITagService tagService;
        private INotificationService notificationService;
        private ApplicationUserManager userManager;

        public ApplicationUserManager UserManager
        {
            get
            {
                return userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
            }
            private set
            {
                userManager = value;
            }
        }

        public HomeController(IPostService postService, IAccountService accountService, IOrgService orgService, ITagService tagService, INotificationService notificationService)
        {
            this.postService = postService;
            this.accountService = accountService;
            this.orgService = orgService;
            this.tagService = tagService;
            this.notificationService = notificationService;
        }

        #region Action

        [ApplicationAuthorize(Permissions = Rights.View + Modules.Conversation)]
        public ActionResult Index(string id, HomeSearchModel searchModel)
        {
            id = string.IsNullOrEmpty(id) ? GlobalVariables.CurrentUser.Id : id;
            GlobalVariables.SelectedUser = accountService.GetById(id);

            if (!ApplicationHelpers.IsManager(accountService, UserManager, GlobalVariables.CurrentUser.Id, GlobalVariables.SelectedUser.Id)
                && GlobalVariables.CurrentUser.Id != GlobalVariables.SelectedUser.Id)
            {
                return RedirectToAction("Index", "Feedback", new { id = id });
            }

            var viewModel = SearchData(id, searchModel);
            return View(viewModel);
        }

        public ActionResult SummaryPartial(string id, HomeSearchModel searchModel)
        {
            var viewModel = SearchData(id, searchModel);
            return PartialView("_Summary", viewModel);
        }

        public ActionResult ConversationPartial(string id, HomeConversationSearchModel searchModel)
        {
            var conversations = postService.SearchConversations(UserManager, searchModel).OrderByDescending(x => x.CreatedOn);
            return PartialView("_Conversation", conversations);
        }

        public ActionResult FeedbackPartial(string id, FeedbackSearchModel searchModel)
        {
            if (searchModel != null)
            {
                searchModel.GivenByMe = false;
            }
            var feedbacks = postService.SearchFeedbacks(UserManager, searchModel).OrderByDescending(x => x.CreatedOn);
            return PartialView("_Feedback", feedbacks);
        }

        public ActionResult SearchAssociates(string q)
        {
            var associates = accountService.Get(a => a.DisplayName.Contains(q)).Take(20).Select(u => new AssociateViewModel
            {
                Id = u.Id,
                DisplayName = u.DisplayName,
                Avatar = u.Avatar,
                Email = Server.UrlEncode(u.Email)
            });
            return Json(associates, JsonRequestBehavior.AllowGet);
        }

        public ActionResult SetSelectedUser(string id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            var user = accountService.GetById(id);
            if (user == null)
            {
                return HttpNotFound();
            }

            GlobalVariables.SelectedUser = user;
            return Json(new
            {
                success = true,
                message = "Successfully",
                email = Server.UrlEncode(id)
            });
        }

        public ActionResult SearchManagers(string q)
        {
            var currentUser = accountService.GetById(GlobalVariables.CurrentUser.Id);
            var associates = accountService.Get(a => a.DisplayName.Contains(q)
                && a.Id != currentUser.Id
                && currentUser.Org.Path.StartsWith(a.Org.Path)
                && a.Manager.Id != currentUser.Id).Select(u => new AssociateViewModel
            {
                Id = u.Id,
                DisplayName = u.DisplayName,
                Avatar = u.Avatar
            });

            return Json(associates, JsonRequestBehavior.AllowGet);
        }

        public ActionResult HeaderPartial()
        {
            AssociateViewModel model = null;
            bool isReportViewer = false;
            bool hasManagerRelationship = false;
            bool isOwner = false;

            if (Request.IsAuthenticated)
            {
                GlobalVariables.SelectedUser = GlobalVariables.SelectedUser ?? GlobalVariables.CurrentUser;

                if (GlobalVariables.CurrentUser != null && GlobalVariables.SelectedUser != null)
                {
                    // Check if the current user is viewing his/her own page
                    isOwner = GlobalVariables.SelectedUser.Id == GlobalVariables.CurrentUser.Id;

                    // Check if the current user is viewing his/her own page
                    hasManagerRelationship = ApplicationHelpers.IsManager(accountService, UserManager, GlobalVariables.CurrentUser.Id, GlobalVariables.SelectedUser.Id);

                    isReportViewer = isOwner && ApplicationHelpers.IsReportViewer(accountService, UserManager, GlobalVariables.CurrentUser.Id);

                    model = new AssociateViewModel
                    {
                        Id = GlobalVariables.SelectedUser.Id,
                        Email = GlobalVariables.SelectedUser.Email,
                        DisplayName = GlobalVariables.SelectedUser.DisplayName,
                        Avatar = GlobalVariables.SelectedUser.Avatar,
                        TotalNotifications = notificationService.GetByUser(GlobalVariables.CurrentUser.Id).Count()
                    };
                }
            }

            // Show [Home] menu
            ViewBag.showHomeMenu = isOwner || hasManagerRelationship;

            // Show [My Notes] menu
            ViewBag.showMyNoteMenu = isOwner;

            // Show [Manager Conversations] menu
            ViewBag.showManagerConversationMenu = isOwner || hasManagerRelationship;

            // Show [Feedback] menu
            ViewBag.showFeedbackMenu = true;

            // Show [Manager Notes] menu
            ViewBag.showManagerNoteMenu = hasManagerRelationship;

            // Show [Manager Report] menu
            ViewBag.showManagerReportMenu = isReportViewer;

            // Show [Role] menu
            var currentUserRoles = UserManager.GetRoles(GlobalVariables.CurrentUser.Id);
            ViewBag.showRoleMenu = currentUserRoles.Contains("Administrator") && isOwner;

            return this.PartialView("_HeaderPartial", model);
        }

        public ActionResult Tags(string name = null)
        {
            var tags = tagService.Get();
            if (!string.IsNullOrEmpty(name))
            {
                tags = tags.Where(t => t.Name.ToUpper().Contains(name.ToUpper()));
            }
            return Json(tags.Select(t => t.Name), JsonRequestBehavior.AllowGet);
        }

        public ActionResult Error()
        {
            return View("~/Views/Shared/Error.cshtml");
        }

        public ActionResult About()
        {
            return View();
        }

        #endregion

        #region Method

        private HomeViewModel SearchData(string id, HomeSearchModel searchModel)
        {
            var viewModel = new HomeViewModel();
            viewModel.Id = id;

            if (searchModel != null)
            {
                viewModel.Year = searchModel.Year;
            }

            // Get conversations from DB
            var conversationSearchModel = new HomeConversationSearchModel
            {
                Statuses = Enum.GetValues(typeof(Emoticon)).Cast<Emoticon>().ToList(),
                Types = Enum.GetValues(typeof(PostType)).Cast<PostType>().ToList()
            };
            conversationSearchModel.Year = viewModel.Year;
            viewModel.Conversations = postService.SearchConversations(UserManager, conversationSearchModel).OrderByDescending(x => x.CreatedOn);

            // Get feedbacks from DB
            var feedbackSearchModel = new FeedbackSearchModel();
            feedbackSearchModel.Year = viewModel.Year;
            feedbackSearchModel.Emoticons = Enum.GetValues(typeof(Emoticon)).Cast<Emoticon>().ToList();
            feedbackSearchModel.GivenByMe = false;
            viewModel.Feedbacks = postService.SearchFeedbacks(UserManager, feedbackSearchModel)
                .OrderByDescending(x => x.CreatedOn);

            // Summarize conversations and feedbacks
            foreach (var emoticon in viewModel.Statuses)
            {
                viewModel.StatusSummaries[emoticon] = viewModel.Conversations.Count(c => c.Emoticon == emoticon);
                viewModel.FeedbackSummaries[emoticon] = viewModel.Feedbacks.Count(f => f.Emoticon == emoticon);
            }
            foreach (var type in viewModel.ConversationTypes)
            {
                viewModel.ClassificationSummaries[type] = viewModel.Conversations.Count(c => c.Type == type);
            }

            // Get notifications from DB
            // Only if the user is viewing his/her own profile
            viewModel.Notifications = GlobalVariables.CurrentUser.Id == id
                ? notificationService.GetByUser(id).Select(n => new NotificationViewModel(n)).OrderByDescending(x => x.CreatedOn)
                : Enumerable.Empty<NotificationViewModel>();

            return viewModel;
        }

        #endregion
    }
}